from datetime import datetime
from decimal import Decimal

from flask import g, current_app
from flask_restful import Resource
from flask_restful.reqparse import RequestParser

from comment.modules import db
from comment.modules.debt_info import Debt_info
from comment.modules.debt_repay import Debtor_repay
from comment.modules.loanApply import Loan
from comment.modules.user import User
from comment.utils.decorators import login_required
from comment.utils.financial_redis import fr
from comment.utils.gen_trans_id import gen_trans_id
from financial.resources.transaction.const import LoanConfig
from financial.resources.transaction.serializer import LoanPaginateSerializer
from dateutil.relativedelta import relativedelta


class LoanApply(Resource):
    method_decorators = [login_required]

    def post(self):
        """申请借款"""
        rp = RequestParser()
        rp.add_argument('holder', required=True)  # 借款人
        rp.add_argument('amount', required=True)  # 金额
        rp.add_argument('code', required=True)  # 验证码
        rp.add_argument('loanMonth', required=True)  # 借款期数

        args = rp.parse_args()
        holder = args.holder
        amount = args.amount
        loan_month = args.loanMonth
        code = args.code

        user_id = g.user_id
        cur_user = User.query.filter(User.id == user_id).first()
        username = cur_user.username

        # 验证，传入的验证码是否正确
        # 从Redis数据库中获取之前保存的验证码

        # try:
        #     real_code = fr.get('registerCode:{}'.format(cur_user.phone))
        #     if not real_code or real_code.decode() != code:  # 数据库中没有code或者存储的code和参数不一致
        #         current_app.logger.info('验证码错误或者时效')
        #         return {'message': '验证码错误或者时效.', 'code': 20001}
        # except ConnectionError as e:
        #     current_app.logger.error(e)
        #     return {'message': '验证码判断的时候，数据库连接错误', 'code': 20001}

        loan_apply = Loan(loanNum=amount, lUid=user_id, duration=loan_month, lName=username,
                          lRate=LoanConfig.YEAR_RATE.value,
                          lRepayDay=datetime.now().day)

        db.session.add(loan_apply)
        db.session.commit()
        return {'msg': 'success'}

    def get(self):
        """管理员看到的借款申请列表"""
        rp = RequestParser()
        rp.add_argument('start')  # 开始时间
        rp.add_argument('end')  # 结束时间
        rp.add_argument('curPage')  # 当前页
        rp.add_argument('perPage')  # 每页数量
        rp.add_argument('approve_status')  # 审批状态

        args = rp.parse_args()
        start = args.get('start')
        end = args.get('end')
        cur_page = int(args.get('curPage'))
        per_page = int(args.get('perPage'))
        status = int(args.get('approve_status'))

        # 过滤查询
        # 第一个过滤条件
        if status > 0:
            loan_list = Loan.query.filter(Loan.status > 0)
        else:
            loan_list = Loan.query.filter(Loan.status == status)

        # 第二个过滤条件，根据时间
        if start and end:
            # 需要根据起始和结束的时间过滤
            loan_list = loan_list.filter(db.cast(Loan.applyDate, db.DATE) >= db.cast(start, db.DATE)) \
                .filter(db.cast(Loan.applyDate, db.DATE) <= db.cast(end, db.DATE)) \
                .paginate(cur_page, per_page, error_out=False)
        else:
            loan_list = loan_list.paginate(cur_page, per_page, error_out=False)

        # 分页数据的序列化
        data = LoanPaginateSerializer(loan_list).to_dict()

        return {'msg': 'success', 'data': data}

    def put(self):
        """审批借款"""
        """修改借款的状态，产生债券，创建还款计划的数据"""
        rp = RequestParser()
        rp.add_argument('applyId')  # 借款申请id
        rp.add_argument('status')  # 借款状态
        args = rp.parse_args()
        loan_id = args.get('applyId')
        status = args.get('status')

        # 查询借款对象
        loan = Loan.query.filter(Loan.id == loan_id).first()
        # 第一步：更新借款的申请状态
        loan.status = int(status)

        if status == '1':
            # 产生债券数据
            debt_no = gen_trans_id('debt')
            debtors_id = loan.user.idNum  # 身份证号
            # 还款的最后时间
            end_date = datetime.now() + relativedelta(months=loan.duration)
            # 创建债权
            new_debt = Debt_info(debtNo=debt_no, debtorsName=loan.lName, loanNo=loan.id, borrowerId=loan.lUid,
                                 debtorsId=debtors_id, loanStartDate=datetime.now(), loanPeriod=loan.duration,
                                 loanEndDate=end_date, repaymentStyle=loan.lRepayType, matchedMoney=0,
                                 repaymenDate=loan.lRepayDay, repaymenMoney=loan.loanNum, matchedStatus=0,
                                 debtMoney=loan.loanNum, debtYearRate=loan.lRate, debtTransferredMoney=0)
            db.session.add(new_debt)
            db.session.flush()
            # 第三步：创建还款计划
            self.create_repay_list(new_debt)
            # 一次性提交事务
        db.session.commit()
        return {'msg': 'success'}

    def create_repay_list(self, new_debt):
        """创建当月的债券还款计划"""

        # 月还款金额：借款的金额 / 借款的期数
        mount_cost = round(new_debt.repaymenMoney / new_debt.loanPeriod, 2)

        # 月利息=年利息/12
        mount_rate = round(LoanConfig.YEAR_RATE.value / 12, 4)

        for m in range(1, new_debt.loanPeriod + 1):
            # 第一期应还的利息 =剩下的本金 * 月利息
            interest = round((new_debt.repaymenMoney - mount_cost * (m - 1)) * Decimal(mount_rate), 2)

            # 每一期应还款的总金额 = 每月的本金 + 每个月的利息
            total = float(round(interest + mount_cost, 2))
            # 创建每一期的还款计划对象
            repay_plan = Debtor_repay(claimsId=new_debt.id, receivableMoney=total,
                                      currentTerm=m, recordDate=datetime.now())
            db.session.add(repay_plan)


class MyLoanApply(Resource):
    """我的借款列表"""

    def get(self):
        rp = RequestParser()
        rp.add_argument('curPage')  # 当前页
        rp.add_argument('perPage')  # 每页数量
        args = rp.parse_args()
        cur_page = int(args.get('curPage'))
        per_page = int(args.get('perPage'))

        user_id = g.user_id
        loan_list = Loan.query.filter(Loan.lUid == user_id).paginate(cur_page, per_page, error_out=False)
        # 分页数据的序列化
        data = LoanPaginateSerializer(loan_list).to_dict()

        return {'msg': 'success', 'data': data}
